package com.deep.schedule.work;

import com.deep.schedule.entity.Work;

import java.text.DecimalFormat;
import java.util.*;

/**
 * @author Deep
 * @date 2021/10/4 13:34
 */
@SuppressWarnings("all")
public class CalculationImpl implements Calculation {

    @Override
    public void fcfs(List<Work> workList) {
        // 按照作业到达时间进行排序
        workList = sortByArriveTime(workList);

        float currentTime = 0;                      // 记录当前时间，从0时刻开始
        for (int i = 0; i < workList.size(); i++) {
            Work work = workList.get(i);
            // 第一个作业或未到达的作业
            if ((i == 0 || work.getArriveTime() > currentTime) && work.isFlag() == false) {
                work.setStartTime(work.getArriveTime());
            } else {    // 已经到达的作业
                if (work.getArriveTime() < currentTime && work.isFlag() == false) {
                    work.setStartTime(workList.get(i - 1).getFinishTime());
                }
            }
            work.setFinishTime(work.getStartTime() + work.getRunTime());
            work.setFlag(true);
            work.setTurnaroundTime(work.getFinishTime() - work.getArriveTime());
            work.setWeightedTurnaroundTime(work.getTurnaroundTime() / work.getRunTime());
            currentTime = work.getFinishTime();
        }

        show(workList);
    }

    @Override
    public void slf(List<Work> workList) {
        float currentTime = 0;                      // 记录当前时间，从0时刻开始
        List<Work> showList = new ArrayList<>();    // 用来存储处理过的作业
        workList = sortByArriveTime(workList);      // 按照程序到达时间进行排序

        int key;                                    // 记录即将处理的程序下标
        for (int i = 0; i < workList.size(); i++) {
            // 第一个到达的程序无条件执行
            if (i == 0) {
                Work work = workList.get(i);
                currentTime += work.getArriveTime();    // 当前时间为第一个作业到达的时间
                work.setStartTime(currentTime);
                currentTime += work.getRunTime();
                work.setFinishTime(currentTime);
                work.setTurnaroundTime(work.getFinishTime() - work.getArriveTime());
                work.setWeightedTurnaroundTime(work.getTurnaroundTime() / work.getRunTime());
                work.setFlag(true);                    // 表示程序已经运行完成
                showList.add(work);
            } else {
                // 获取等待队列中最短运行时间的作业下标
                key = selectByShortRunTime(workList, currentTime);
                if (key != -1) {
                    Work work = workList.get(key);
                    // 当前时间为上一个作业结束的时间
                    currentTime = showList.get(showList.size() - 1).getFinishTime();
                    work.setStartTime(currentTime);
                    currentTime += work.getRunTime();
                    work.setFinishTime(currentTime);
                    work.setTurnaroundTime(work.getFinishTime() - work.getArriveTime());
                    work.setWeightedTurnaroundTime(work.getTurnaroundTime() / work.getRunTime());
                    work.setFlag(true);
                    showList.add(work);
                }
            }
        }
        show(showList);
    }

    /**
     * 返回等待作业中最短运行时间的下标
     *
     * @param workList    待处理的作业
     * @param currentTime 当前时刻
     * @return
     */
    public int selectByShortRunTime(List<Work> workList, float currentTime) {
        int minIndex = 0;                             // 记录等待程序的最小变量的下标
        float minRunTime = Float.POSITIVE_INFINITY;   // 辅助变量用来进行存储最小运行时间

        for (int i = 0; i < workList.size(); i++) {
            // 条件判断：作业未运行完且已经到达
            if (workList.get(i).isFlag() == false && workList.get(i).getArriveTime() <= currentTime) {
                // 寻找正在等待的作业的最小值
                if (workList.get(i).getRunTime() < minRunTime) {
                    minRunTime = workList.get(i).getRunTime();
                    minIndex = i;
                }
            }
        }
        return minIndex;
    }

    /**
     * 对所有进程按照到达时间进行排序
     *
     * @param workList 待处理作业
     * @return 作业队列
     */
    public List<Work> sortByArriveTime(List<Work> workList) {
        Collections.sort(workList, Comparator.comparingDouble(Work::getArriveTime));
        return workList;
    }

    /**
     * 展示作业处理后的结果
     *
     * @param workList
     */
    public static void show(List<Work> workList) {
        System.out.println("作业\t" + "开始时间\t" + "完成时间\t" + "周转时间\t" + "带权周转时间");
        DecimalFormat df = new DecimalFormat("0.00");
        for (Work work : workList) {
            System.out.println(work.getName() + "\t"
                    + df.format(work.getStartTime()) + "\t"
                    + df.format(work.getFinishTime()) + "\t"
                    + df.format(work.getTurnaroundTime()) + "\t"
                    + df.format(work.getWeightedTurnaroundTime())
            );
        }
    }
}
